/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.wonderly.desk.contacts;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
import org.openide.util.lookup.ServiceProvider;

/**
 *
 * @author gregg
 */
@ServiceProvider(service=ContactLogger.class)
public class ContactLoggerImpl implements ContactLogger {
	private volatile ConcurrentHashMap<String,List<Contact>>contacts =
		new ConcurrentHashMap<String,List<Contact>>();
	private volatile boolean success;

	protected String getStoreLocation() {
		return System.getProperty("user.home").replace("\\","/")+"/.hamdesk/contacts";
	}

	public ContactLoggerImpl() throws IOException, ClassNotFoundException {
		// Loading module, get last known contacts.
		readContacts();
	}

	public boolean contactsLoaded() {
		return success;
	}

	public void readContacts() throws IOException, ClassNotFoundException {
		File f = new File( getStoreLocation() );
		if( f.mkdirs() == false )
			throw new IOException("Can't create directory for contact measurements: "+f);
		if( f.exists() ) {
			FileInputStream fs = new FileInputStream( f );
			try {
				ObjectInputStream is = new ObjectInputStream( fs );
				contacts = (ConcurrentHashMap<String,List<Contact>>)is.readObject();
			} finally {
				fs.close();
			}
		}

	}
	public List<Contact> findContactsLike(String regex) {
		Pattern r = Pattern.compile( regex );
		List<Contact> l = new ArrayList<Contact>();
		for( String call : contacts.keySet() ) {
			if( r.matcher( call ).matches() ) {
				l.addAll( contacts.get( call ) );
			}
		}
		return l;
	}

	public List<Contact> findContactsWith(String callSign) {
		return contacts.get( callSign );
	}

	public void logContact(Contact contact) {
		List<Contact> l = contacts.get(contact.getContact());
		if( l == null ) {
			contacts.putIfAbsent( contact.getContact(), new ArrayList<Contact>() );
			l = contacts.get( contact.getContact() );
		}
		synchronized( l ) {
			l.add( contact );
		}
	}

	public List<Contact> findContactsOn(Date day) {
		List<Contact> l = new ArrayList<Contact>();
		for( String call : contacts.keySet() ) {
			for( Contact cl : contacts.get( call ) ) {
				if( sameDay( day, new Date( cl.getTime() ) )) {
					l.addAll( contacts.get( call ) );
				}
			}
		}
		return l;
	}

	private boolean sameDay( Date theDay, Date checkDay ) {
		GregorianCalendar gct = new GregorianCalendar();
		gct.setTime(theDay);
		GregorianCalendar gcc = new GregorianCalendar();
		gcc.setTime(checkDay);
		return
			( gct.get(Calendar.YEAR) == gcc.get(Calendar.YEAR) ) &&
			( gct.get(Calendar.MONTH) == gcc.get(Calendar.MONTH) ) &&
			( gct.get(Calendar.DAY_OF_MONTH) == gcc.get(Calendar.DAY_OF_MONTH) );
	}

	public List<Contact> findContactsDuring(Date start, Date last) {
		List<Contact> l = new ArrayList<Contact>();
		for( String call : contacts.keySet() ) {
			for( Contact cl : contacts.get( call ) ) {
				if( duringInterval( start, last, new Date( cl.getTime() ) )) {
					l.addAll( contacts.get( call ) );
				}
			}
		}
		return l;
	}

	public List<Contact> findContactsOn(Date day, String theCall) {
		List<Contact> l = new ArrayList<Contact>();
		for( String call : contacts.keySet() ) {
			for( Contact cl : contacts.get( call ) ) {
				if( cl.getContact().equals(theCall) && sameDay( day, new Date( cl.getTime() ) )) {
					l.addAll( contacts.get( call ) );
				}
			}
		}
		return l;
	}

	public List<Contact> findContactsDuring(Date start, Date last, String theCall) {
		List<Contact> l = new ArrayList<Contact>();
		for( String call : contacts.keySet() ) {
			for( Contact cl : contacts.get( call ) ) {
				if( cl.getContact().equals(theCall) && duringInterval( start, last, new Date( cl.getTime() ) )) {
					l.addAll( contacts.get( call ) );
				}
			}
		}
		return l;
	}

	private boolean duringInterval(Date start, Date last, Date checkDay) {
		GregorianCalendar gcf = new GregorianCalendar();
		gcf.setTime(start);
		GregorianCalendar gct = new GregorianCalendar();
		gct.setTime(last);
		GregorianCalendar gcc = new GregorianCalendar();
		gcc.setTime(checkDay);
		return
			( gcf.get(Calendar.YEAR) >= gcc.get(Calendar.YEAR) ) &&
			( gcf.get(Calendar.MONTH) >= gcc.get(Calendar.MONTH) ) &&
			( gcf.get(Calendar.DAY_OF_MONTH) >= gcc.get(Calendar.DAY_OF_MONTH) &&
			( gct.get(Calendar.YEAR) <= gcc.get(Calendar.YEAR) ) &&
			( gct.get(Calendar.MONTH) <= gcc.get(Calendar.MONTH) ) &&
			( gct.get(Calendar.DAY_OF_MONTH) <= gcc.get(Calendar.DAY_OF_MONTH) ) );
	}
}
